﻿#include <SDL/SDL_image.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include "BreakerMap.h"
#include "Utils\\Rect.h"
#include "HUDScreen.h"

using namespace SDL::UTILS;
using namespace SDL::ELEMENTS;

HUDArgs::HUDArgs(SDL_Surface* _screen, SDL_Event* _event,
				SDL::UTILS::Surface& _loadedBackground,
				std::string& _backgroundFile, std::wstring& _mapFile,
				Bloc*& _currentBloc,
				BlocManager& _blocs, bool& _showGrid)
	: ScreenArgs(_screen, _event), LoadedBackground(_loadedBackground),
	BackgroundFile(_backgroundFile), MapFile(_mapFile),
	CurrentBloc(_currentBloc), Blocs(_blocs), ShowGrid(_showGrid)
{
	HUDScreen::SetTilesPositions(_blocs);
}

HUDArgs::~HUDArgs()
{
}

HUDScreen::HUDScreen()
	: IScreen(), m_background(IMG_Load("editor_background.png")),
	m_cursor("tilescursor.png"), m_tiles(""), m_pbNew(L"New"), m_pbReset(L"Reset"),
	m_pbSave(L"Save"), m_pbSaveAs(L"Save as"),
	m_pbLoad(L"Load map"), m_pbBackground(L"Background"),
	m_cbShowGrid(L"Show grid")
{
	m_background.SetColorKey(0xFF00FF);
	this->InitButtons();
	SDL_Surface* s = SDL_CreateRGBSurface(SDL_HWSURFACE, 160, 190, 32, 0, 0, 0, 0);
	m_tiles.GetSurface()->SetSurface(s);
	m_tiles.SetPosition(839, 512);
	m_cursor.SetPosition(839, 512);
}

HUDScreen::~HUDScreen()
{
}

void HUDScreen::SetTilesPositions(BlocManager& _blocs)
{
	std::vector<Bloc*> blocs;
	_blocs.GetOriginals(blocs);
	int max = blocs.size();
	int x = 0, y = 0;
	for (int i = 0; i < max; i++)
	{
		blocs[i]->SetPosition(x, y);
		x += 32;
		if (x >= 160)
		{
			y += 16;
			x = 0;
			if (y >= 190)
				break ;
		}
	}
}

void HUDScreen::Draw(IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);

	SDL_FillRect(m_tiles.GetSurface()->GetSurface(), NULL, 0x008000);

	m_background.BlitSurface(NULL, ha->Screen, NULL);
	m_pbNew.Draw(ha->Screen);
	m_pbReset.Draw(ha->Screen);
	m_pbSave.Draw(ha->Screen);
	m_pbSaveAs.Draw(ha->Screen);
	m_pbLoad.Draw(ha->Screen);
	m_pbBackground.Draw(ha->Screen);
	m_cbShowGrid.Draw(ha->Screen);

	std::vector<Bloc*> blocs;
	ha->Blocs.GetOriginals(blocs);
	int max = blocs.size();
	for (int i = 0; i < max; i++)
		blocs[i]->Draw(m_tiles.GetSurface()->GetSurface());
	m_tiles.Draw(ha->Screen);
	if (ha->CurrentBloc != NULL)
	{
		m_cursor.SetPosition(839 + ha->CurrentBloc->GetPosition().GetX(),
							 512 + ha->CurrentBloc->GetPosition().GetY());
		m_cursor.Draw(ha->Screen);
	}
}

void HUDScreen::Exec(IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);
	
	m_pbNew.UpdateState();
	m_pbReset.UpdateState();
	m_pbSave.UpdateState();
	m_pbSaveAs.UpdateState();
	m_pbLoad.UpdateState();
	m_pbBackground.UpdateState();
	m_cbShowGrid.UpdateState();

	ha->ShowGrid = m_cbShowGrid.IsChecked();
	
	int blocNumber = ha->Blocs.GetOriginals().size();

	if (blocNumber > 0)
		this->MoveCursorInTiles(blocNumber, ha);
	
	if (ha->MapFile == L"")
		m_pbSave.SetDisabled(true);
	else
		m_pbSave.SetDisabled(false);
}

bool HUDScreen::Manage(ScreenManager::Element* _caller, IArgs* _args)
{
	HUDScreen* hs = dynamic_cast<HUDScreen*>(_caller->Object);

	if (hs->m_pbNew.GetState() == SDL::BUTTON::STATE::CLICKED)
		hs->On_pbNew_Clicked(_caller->Datas);
	if (hs->m_pbReset.GetState() == SDL::BUTTON::STATE::CLICKED)
		hs->On_pbReset_Clicked(_caller->Datas);
	if (hs->m_pbSaveAs.GetState() == SDL::BUTTON::STATE::CLICKED)
		hs->On_pbSaveAs_Clicked(_caller->Datas);
	if (hs->m_pbSave.GetState() == SDL::BUTTON::STATE::CLICKED)
		hs->On_pbSave_Clicked(_caller->Datas);
	if (hs->m_pbLoad.GetState() == SDL::BUTTON::STATE::CLICKED)
		hs->On_pbLoad_Clicked(_caller->Datas);
	if (hs->m_pbBackground.GetState() == SDL::BUTTON::STATE::CLICKED)
		hs->On_pbBackground_Clicked(_caller->Datas);

	return (true);
}

void HUDScreen::InitButtons()
{
	Rect upperRight(824, 0, 200, 512);
	Sint16 xbutton = upperRight.x +
					(upperRight.w / 2 - m_pbSave.GetDefaultSize().w / 2);
	Sint16 ybutton = 112;
	
	m_pbNew.SetPosition(xbutton, ybutton);
	ybutton += 48;
	m_pbReset.SetPosition(xbutton, ybutton);
	ybutton += 48;
	m_pbSave.SetPosition(xbutton, ybutton);
	ybutton += 48;
	m_pbSaveAs.SetPosition(xbutton, ybutton);
	ybutton += 48;
	m_pbLoad.SetPosition(xbutton, ybutton);
	ybutton += 48;
	m_pbBackground.SetPosition(xbutton, ybutton);
	ybutton += 48;
	m_cbShowGrid.SetPosition(xbutton, ybutton);
	ybutton += 48;
}

void HUDScreen::MoveCursorInTiles(int _blocNumber, HUDArgs* _args)
{
	int x = 0, y = 0;
	Uint8 button = SDL_GetMouseState(&x, &y);
	Uint16 w = 0, h = 0;
	h = 16 + ((_blocNumber * 32) / 160) * 16;
	if (h == 1)
		//w = (_blocNumber - (((h / 16) - 1) * 5)) * 32;
		w = _blocNumber * 32;
	else
		w = 5 * 32;
	Rect area(m_tiles.GetPosition().GetX(), m_tiles.GetPosition().GetY(),
				w - 1, h - 1);
	if (area.IsInArea(Rect(x, y), area) == true)
	{
		//SDL_ShowCursor(0);
		int x2 = area.x + (((x - area.x) / 32) * 32);
		int y2 = area.y + (((y - area.y) / 16) * 16);
		//m_cursor.SetPosition(x2, y2);

		if (button & SDL_BUTTON_LMASK)
		{
			std::vector<Bloc*> blocs;
			_args->Blocs.GetOriginals(blocs);
			int max = blocs.size();
			for (int i = 0; i < max; i++)
			{
				if (blocs[i]->GetPosition().GetX() == x2 - 839 &&
					blocs[i]->GetPosition().y == y2 - 512)
				{
					_args->CurrentBloc = blocs[i];
				}
			}
		}
	}
	//else
	//	SDL_ShowCursor(1);
}

// http://forum.hardware.fr/hfr/Programmation/C-2/enregistrement-repertoire-possible-sujet_26602_1.htm
// http://stackoverflow.com/questions/454811/opening-an-opendialog-from-vis-c-console-app
static bool FileDlg(std::wstring& _path, wchar_t* _defaultName,
					wchar_t* _defaultExt, BOOL (__stdcall *func)(OPENFILENAME*),
					std::wstring const& _initialDir = L".",
					wchar_t const* _filter = L"All Files (*.*)\0*.*\0\0")
{
	//char FilterSpec =
	//	"Object Files(.obj)\0*.obj\0Text Files(.txt)\0.txt\0All Files(.)\0*.*\0"
	wchar_t* path = _defaultName;
	int size = 42000;

	/*
	Renvoit TRUE si un nom de fichier a été donné (click sur OK)
	FALSE si l'utilisateur a annulé ou s'il il y a eu une erreur
	Name contient le nom complet valide (avec le chenmin)
	*/
	OPENFILENAME ofn;
	ZeroMemory(&ofn, sizeof(ofn)); // tout initialiser a zero
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.lpstrFile = (LPWSTR)path;
	ofn.nMaxFile = size;
	ofn.Flags = OFN_PATHMUSTEXIST |  // chemin valide
		OFN_OVERWRITEPROMPT; // demander avant de remplacer un fichier existant
	ofn.lpstrDefExt = _defaultExt;
	ofn.lpstrInitialDir = _initialDir.c_str();
	ofn.lpstrFilter = _filter;

	wchar_t currentDirectory[42000];
	GetCurrentDirectory(42000, currentDirectory);
	if (func(&ofn) == true)
	{
		_wchdir(currentDirectory);
		_path = path;
		return (true);
	}
	return (false);
}

void HUDScreen::On_pbNew_Clicked(IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);

	ha->Blocs.Clear();
	ha->BackgroundFile = "default.png";
	ha->MapFile = L"";
	std::string s = "Backgrounds\\";
	s += ha->BackgroundFile;
	ha->LoadedBackground.SetSurface(IMG_Load(s.c_str()));
}

void HUDScreen::On_pbReset_Clicked(IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);

	ha->Blocs.Clear();
}

void HUDScreen::On_pbSaveAs_Clicked(IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);
	std::wstring path;
	wchar_t wPath[42000] = L"No name.map";

	if (FileDlg(path, wPath, L".map", GetSaveFileName,
				L"maps", L"Map Files (*.map)\0*.map\0\0") == true)
	{
		BreakerMap::Save(ha->BackgroundFile, path, ha->Blocs);
		ha->MapFile = wPath;
	}
}

void HUDScreen::On_pbSave_Clicked(IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);

	if (ha->MapFile != L"")
	{
		BreakerMap::Save(ha->BackgroundFile, ha->MapFile, ha->Blocs);
	}
}

static void LoadBackground(std::wstring const& _path, HUDArgs* _ha)
{
	std::string background = Font::WStringToString(_path);

	std::string s = "Backgrounds\\";
	int offset = background.find_last_of("/\\");
	if (offset != std::string::npos)
		s += background.substr(offset);
	else
		s += background;
	std::ifstream ifs(s.c_str());
	if (ifs.fail())
	{
		std::cerr << "Couldn't find " << s << ". Loading default background."
				  << std::endl;
		background = "default.png";
		s = "Backgrounds\\";
		s += background;
	}
	ifs.close();
	_ha->BackgroundFile = s;
	std::string m_backgroundFile = _ha->BackgroundFile;
	SDL_Surface* surface = IMG_Load(s.c_str());
	if (surface == NULL)
		std::cerr << SDL_GetError() << std::endl;
	_ha->LoadedBackground.SetSurface(surface);
}

void HUDScreen::On_pbLoad_Clicked(SDL::UTILS::IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);
	std::wstring path;
	wchar_t wPath[42000] = L"No name.map";

	if (FileDlg(path, wPath, L".map", GetOpenFileName,
				L"maps", L"Map Files (*.map)\0*.map\0\0") == true)
	{
		std::string background;
		BreakerMap::Load(&background, path, ha->Blocs);
		ha->CurrentBloc = ha->Blocs.Find("normal");
		HUDScreen::SetTilesPositions(ha->Blocs);
		ha->MapFile = path;

		LoadBackground(Font::StringToWString(background), ha);
	}
}

void HUDScreen::On_pbBackground_Clicked(SDL::UTILS::IArgs* _datas)
{
	HUDArgs* ha = dynamic_cast<HUDArgs*>(_datas);
	std::wstring path;
	wchar_t wPath[42000] = L"default.png";
	
	if (FileDlg(path, wPath, L"Image(*.png), *.png", GetOpenFileName,
				L"Backgrounds", L"PNG Files (*.png)\0*.png\0\0") == true)
		LoadBackground(wPath, ha);
}
